using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.Windows.Forms;

namespace Jonathan
{
    public delegate void ListItemChange(object sender, EventArgs e);

    public class ListControl : UserControl
    {
        #region - Variables -

        private ListItemCollection m_Items;
        private int m_TopIndex;
        private VScrollBar m_VScroll;
        private bool m_AllowMulti;
        private TextBox _txtFind;
        private ToolTip m_TTMain;

        public event ListItemChange SelectedItemChange;
        #endregion

        #region - Constructor -

        public ListControl()
        {
            this.m_Items = new ListItemCollection(this);
            this.BackColor = Color.White;
            this.m_TopIndex = 0;
            this.m_AllowMulti = false;
            this.m_TTMain = new ToolTip();

            this.InitializeComponent();
            this.m_VScroll.Size = new Size(SystemInformation.VerticalScrollBarWidth, this.Height - 3 - this._txtFind.Height);

            // Set Custom Paint Styles...
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);

            this.SelectedItemChange += new ListItemChange(ListControl_SelectedItemChange);
        }

        #endregion

        #region - Properties -

        /// <summary>
        /// Gets or Sets the Items of the ListControl...
        /// </summary>
        public ListItemCollection Items
        {
            get { return this.m_Items; }

            set
            {
                this.m_Items = value;
                this.CheckScroll();
            }
        }

        /// <summary>
        /// Gets or Sets the Index of the Selected Item...
        /// </summary>
        public int SelectedIndex
        {
            get
            {
                for (int a = 0; a < this.m_Items.Count; a++)
                {
                    if (this.m_Items[a].Selected)
                    {
                        return a;
                    }
                }

                return -1;
            }

            set
            {
                if (value >= 0 && value < this.m_Items.Count)
                {
                    this.ClearSelection();
                    this.m_Items[value].Selected = true;
                    this.m_TopIndex = value;
                    if (value > this.m_VScroll.Maximum)
                        this.m_VScroll.Value = this.m_VScroll.Maximum;
                    else
                        this.m_VScroll.Value = value;
                    this.Refresh();
                    this.SelectedItemChange(this.m_Items[value], new EventArgs());
                }
            }
        }

        /// <summary>
        /// Gets an array of Selected Indexes...
        /// </summary>
        public int[] SelectedIndexes
        {
            get
            {
                ArrayList lst = new ArrayList();
                int a = 0;
                for (a = 0; a < this.m_Items.Count; a++)
                {
                    if (this.m_Items[a].Selected)
                    {
                        lst.Add(a);
                    }
                }

                int[] list = new int[lst.Count];
                for (a = 0; a < lst.Count; a++)
                {
                    list[a] = Convert.ToInt32(lst[a]);
                }

                return list;
            }
        }

        /// <summary>
        /// Gets or Sets the Collection of the Selected Items...
        /// </summary>
        public ListItemCollection SelectedItems
        {
            get
            {
                ListItemCollection lic = new ListItemCollection(this);
                for (int a = 0; a < this.m_Items.Count; a++)
                {
                    if (this.m_Items[a].Selected)
                    {
                        lic.Add(this.m_Items[a]);
                    }
                }
                return lic;
            }

            set
            {
                this.ClearSelection();
                if (value.Count > 0)
                {
                    foreach (ListItem li in value)
                    {
                        li.Selected = true;
                    }
                    this.m_TopIndex = this.Items.IndexOf(value[0]);
                    this.SelectedItemChange(value, new EventArgs());
                    this.Refresh();
                    if (this.m_TopIndex > this.m_VScroll.Maximum)
                        this.m_VScroll.Value = this.m_VScroll.Maximum;
                    else
                        this.m_VScroll.Value = this.m_TopIndex;
                }
            }
        }

        /// <summary>
        /// Gets the Selected Text...
        /// </summary>
        public string SelectedText
        {
            get
            {
                for (int a = 0; a < this.m_Items.Count; a++)
                {
                    if (this.m_Items[a].Selected)
                    {
                        return this.m_Items[a].Text;
                    }
                }

                return "";
            }
        }

        /// <summary>
        /// Gets the Selected Value...
        /// </summary>
        public object SelectedValue
        {
            get
            {
                for (int a = 0; a < this.m_Items.Count; a++)
                {
                    if (this.m_Items[a].Selected)
                    {
                        return this.m_Items[a].Value;
                    }
                }

                return null;
            }
        }

        /// <summary>
        /// Gets or Sets the Selected Item...
        /// </summary>
        public ListItem SelectedItem
        {
            get
            {
                for (int a = 0; a < this.m_Items.Count; a++)
                {
                    if (this.m_Items[a].Selected)
                    {
                        return this.m_Items[a];
                    }
                }

                return null;
            }

            set
            {
                for (int a = 0; a < this.m_Items.Count; a++)
                {
                    if (this.m_Items[a] == value)
                    {
                        this.ClearSelection();
                        this.m_Items[a].Selected = true;
                        this.m_TopIndex = a;
                        this.Refresh();
                        this.SelectedItemChange(value, new EventArgs());
                        if (a > this.m_VScroll.Maximum)
                            this.m_VScroll.Value = this.m_VScroll.Maximum;
                        else
                            this.m_VScroll.Value = a;
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// Gets a Count of how many items are selected...
        /// </summary>
        public int SelectionCount
        {
            get
            {
                int count = 0;
                for (int a = 0; a < this.m_Items.Count; a++)
                {
                    if (this.m_Items[a].Selected)
                    {
                        count++;
                    }
                }
                return count;
            }
        }

        /// <summary>
        /// Gets or Sets if the Control will allow multiple selections...
        /// </summary>
        public bool AllowMutltipleSelection
        {
            get { return this.m_AllowMulti; }

            set { this.m_AllowMulti = value; }
        }

        /// <summary>
        /// Gets the proper height of this control...
        /// </summary>
        private int RealHeight
        {
            get { return this.Height - ((this._txtFind.Visible) ? this._txtFind.Height : 0); }
        }

        /// <summary>
        /// Gets or Sets whether to show or hide the find text box...
        /// </summary>
        private bool ShowFindText
        {
            get { return this._txtFind.Visible; }
            set { this._txtFind.Visible = value; }
        }

        #endregion

        #region - Scroll -

        internal void CheckScroll()
        {
            int height = TextRenderer.MeasureText(this.CreateGraphics(), "Ty", this.Font,
                new Size(int.MaxValue, int.MaxValue), TextFormatFlags.VerticalCenter).Height + 2;
            this.m_VScroll.LargeChange = this.RealHeight / height;
            if (height * this.m_Items.Count > this.RealHeight)
            {
                this.m_VScroll.Maximum = this.Items.Count/* - (int)(this.RealHeight / height)*/;
                this.m_VScroll.Visible = true;
                //this.Invalidate(true);
            }
            else
            {
                this.m_TopIndex = 0;
                this.m_VScroll.Visible = false;
                this.Invalidate(true);
            }
        }

        private void m_VScroll_Scroll(object sender, ScrollEventArgs e)
        {
            this.m_TopIndex = e.NewValue;

            this.Invalidate(true);
        }

        #endregion

        #region - Paint -

        protected override void OnPaint(PaintEventArgs e)
        {
            int height = TextRenderer.MeasureText(e.Graphics, "Ty", this.Font, new Size(int.MaxValue, int.MaxValue), TextFormatFlags.VerticalCenter).Height + 2;
            int top = 2;
            if (this.m_Items.Count <= 0)
            {
                StringFormat sfmt = new StringFormat();
                sfmt.FormatFlags = StringFormatFlags.NoClip;
                e.Graphics.DrawString("Loading List...", this.Font, Brushes.Black, new RectangleF(0, 0,this.Width, this.Height), sfmt);
            }
            else
            {
                for (int a = m_TopIndex; a < this.m_Items.Count; a++)
                {
                    this.m_Items[a].Top = top;
                    if (this.m_VScroll.Visible)
                    {
                        this.m_Items[a].Width = this.Width - SystemInformation.VerticalScrollBarWidth - 5;
                    }
                    else
                    {
                        this.m_Items[a].Width = this.Width - 5;
                    }
                    this.m_Items[a].Height = height;
                    this.m_Items[a].PaintItem(e.Graphics, this.Font);
                    top += height;
                    if (top > this.RealHeight)
                    {
                        break;
                    }
                }
            }
            base.OnPaint(e);
        }

        #endregion

        #region - Resize -

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            this.CheckScroll();
            this.Invalidate();
        }

        #endregion

        #region - Mouse Down -

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            this.Focus();

            int height = TextRenderer.MeasureText(this.CreateGraphics(), "Ty", this.Font, 
                new Size(int.MaxValue, int.MaxValue), TextFormatFlags.VerticalCenter).Height + 2;

            int top = 0;
            for (int a = m_TopIndex; a < this.m_Items.Count; a++)
            {
                if (top + height > e.Y)
                {
                    if (Control.ModifierKeys == Keys.Control && this.m_AllowMulti)
                    {
                        if (this.m_Items[a].Selected)
                        {
                            if (this.SelectionCount > 1)
                            {
                                this.m_Items[a].Selected = false;
                            }
                        }
                        else
                        {
                            this.m_Items[a].Selected = true;
                        }
                    }
                    else if (Control.ModifierKeys == Keys.Shift && this.m_AllowMulti)
                    {
                        int selIndex = this.SelectedIndex;
                        if (selIndex > a)
                        {
                            for (int b = a; b <= selIndex; b++)
                            {
                                this.m_Items[b].Selected = true;
                            }
                        }
                        else
                        {
                            for (int b = selIndex; b <= a; b++)
                            {
                                this.m_Items[b].Selected = true;
                            }
                        }
                    }
                    else
                    {
                        this.ClearSelection();
                        this.m_Items[a].Selected = true;
                    }

                    this.SelectedItemChange(this.m_Items[a], new EventArgs());
                    break;
                }
                else
                {
                    top += height;
                }
            }
            this.Invalidate(true);
        }

        #endregion

        #region - Mouse Wheel -

        protected override void OnMouseWheel (MouseEventArgs e)
        {
            if (e.Delta > 0)
            {
                int val = this.m_VScroll.Value - 3;
                if (val < 0)
                    this.m_VScroll.Value = 0;
                else
                    this.m_VScroll.Value = val;
            }
            else
            {
                int val = this.m_VScroll.Value + 3;
                if (val > this.m_VScroll.Maximum)
                    this.m_VScroll.Value = this.m_VScroll.Maximum;
                else
                    this.m_VScroll.Value = val;
            }
            this.m_VScroll_Scroll(this.m_VScroll, new ScrollEventArgs(ScrollEventType.ThumbPosition, this.m_VScroll.Value));
            base.OnMouseWheel(e);
        }

        #endregion

        #region - Clear Selection -

        private void ClearSelection()
        {
            for (int b = 0; b < this.m_Items.Count; b++)
            {
                if (this.m_Items[b].Selected)
                {
                    this.m_Items[b].Selected = false;
                }
            }
        }

        #endregion

        protected override void OnMouseHover (EventArgs e)
        {
            base.OnMouseHover(e);
        }

        private void ListControl_SelectedItemChange(object sender, EventArgs e)
        {
            
        }

        void Find_KeyUp (object sender, KeyEventArgs e)
        {
            string text = this._txtFind.Text.Trim().ToLower();
            if(!string.IsNullOrEmpty(text))
            {
            foreach (ListItem li in this.m_Items)
            {
                if (li.Text.ToLower().IndexOf(text) == 0)
                {
                    this.SelectedItem = li;
                    return;
                }
            }
            }
        }

        #region - Initialize Component -

        private void InitializeComponent ()
        {
            this._txtFind = new System.Windows.Forms.TextBox();
            this.m_VScroll = new VScrollBar();
            this.SuspendLayout();
            // 
            // _txtFind
            // 
            this._txtFind.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this._txtFind.Dock = System.Windows.Forms.DockStyle.Bottom;
            this._txtFind.Location = new System.Drawing.Point(0, 260);
            this._txtFind.Name = "_txtFind";
            this._txtFind.Size = new System.Drawing.Size(150, 20);
            this._txtFind.TabIndex = 0;
            this._txtFind.KeyUp += new KeyEventHandler(Find_KeyUp);
            //
            //
            //
            this.m_VScroll.Location = new Point(this.Width - SystemInformation.VerticalScrollBarWidth - 1, 1);
            this.m_VScroll.Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Right;
            this.m_VScroll.Visible = false;
            this.m_VScroll.LargeChange = 1;
            this.m_VScroll.Scroll += new ScrollEventHandler(m_VScroll_Scroll);
            // 
            // ListControl
            // 
            this.Controls.Add(this._txtFind);
            this.Controls.Add(this.m_VScroll);
            this.Name = "ListControl";
            this.Size = new System.Drawing.Size(150, 280);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion
    }
}
